/* eslint-disable no-underscore-dangle */
/**
 * 深拷贝对象或者合并对象
 * @param {Object} newobj 要合并属性的对象, 不传入时回返回一个深拷贝完成的对象
 * @param {Object || Array} oldobj 要拷贝的对象, 不传入 newobj时, 第二个参数可传入为 passkey, 返回一个深拷贝完成的对象
 * @param {String} paramsStr 参数字符串，passkey=a,b,c,d  passkey(要跳过拷贝的key)
 */
export default function deepCopy(newobj, oldobj, paramsStr) {
  if (oldobj instanceof Array && oldobj.length < 1) return newobj;
  const re = /[a-zA-Z]+=([a-zA-Z]+,?)+$/;
  if (oldobj) {
    if (typeof oldobj === 'string') {
      if (oldobj && !re.test(oldobj)) {
        throw new Error('请检查 paramsStr 传入格式是否正确');
      } else if (newobj instanceof Array) {
        // todo 可以传入 passkey=0,1,2,4 跳过指定索引的拷贝
        // throw new Error('当第二个参数传入字符串时会被认定为 paramsStr, paramsStr无法对数组进行处理,请正确传入参数');
        const _oldobj = newobj;
        const _paramsStr = oldobj;
        const _newobj = [];
        return deepCopy(_newobj, _oldobj, _paramsStr);
      } else {
        const _oldobj = newobj;
        const _paramsStr = oldobj;
        const _newobj = {};
        return deepCopy(_newobj, _oldobj, _paramsStr);
      }
    }

    if (paramsStr && typeof paramsStr === 'string' && !re.test(paramsStr)) throw new Error('请检查 paramsStr 传入格式是否正确');
    const _newobj = newobj;
    const passkeyRe = /passkey=([a-zA-Z]+,?)+/g;
    const passkeyStr = passkeyRe.test(paramsStr) ? paramsStr.match(passkeyRe)[0] : '';
    const passkeys = passkeyStr ? passkeyStr.replace('passkey=', '').split(',') : [];
    Object.keys(oldobj).forEach((k) => {
      if (re.test(paramsStr)) {
        if (passkeys.includes(k)) return;
      }
      const item = oldobj[k];
      if (item instanceof Array) {
        _newobj[k] = [];
        deepCopy(_newobj[k], item, paramsStr);
      } else if (item instanceof Object) {
        _newobj[k] = {};
        deepCopy(_newobj[k], item, paramsStr);
      } else {
        // todo 合并数组: 此处会覆盖 newobj 数组索引 newobj[k(0)] = item,造成无法合并2个数组
        _newobj[k] = item;
      }
    });
  } else {
    const _oldobj = newobj;
    if (_oldobj instanceof Array) {
      const _newobj = [];
      if (_oldobj.every((item) => typeof item === 'string')) {
        _oldobj.forEach((item) => {
          _newobj.push(item);
        });
        return _newobj;
      }
      return deepCopy(_newobj, _oldobj);
    }
    const _newobj = {};
    return deepCopy(_newobj, _oldobj);
  }
  return newobj;
}
